package com.inspur.edp.formserver.vmmanager.voguide;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.cef.designtime.api.util.MetadataUtil;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.accessory.AccessoryService;
import com.inspur.edp.formserver.viewmodel.common.ConvertUtils;
import com.inspur.edp.formserver.viewmodel.exception.ViewModelException;
import com.inspur.edp.formserver.viewmodel.extendinfo.api.GspVoExtendInfoService;
import com.inspur.edp.formserver.viewmodel.extendinfo.entity.GspVoExtendInfo;
import com.inspur.edp.formserver.vmmanager.accessory.ApprovalLogType;
import com.inspur.edp.formserver.vmmanager.exception.VoManagerErrorCodes;
import com.inspur.edp.formserver.vmmanager.util.CheckInfoUtil;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationService;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class VoGuideUtil {

    private VoGuideUtil() {
    }

    public static VoGuideUtil instance;

    public static VoGuideUtil getInstance() {
        if (instance == null) {
            return new VoGuideUtil();
        }
        return instance;
    }

    private String VOGUIDE_VO_METADATATYPE = "GSPViewModel";
    private String VOGUIDE_EXTEND_CONFIG_APPROVAL = "APPROVAL_LOG";

    // region 服务工具
    private AccessoryService accessoryService;

    private AccessoryService getAccessoryService() {
        if (accessoryService == null) {
            accessoryService = SpringBeanUtils.getBean(AccessoryService.class);
        }
        return accessoryService;
    }

    private CustomizationService customizationService;

    private CustomizationService getCustomizationService() {
        if (customizationService == null) {
            customizationService = SpringBeanUtils.getBean(CustomizationService.class);
        }
        return customizationService;
    }

    private GspVoExtendInfoService gspVoExtendInfoService;

    private GspVoExtendInfoService getGspVoExtendInfoService() {
        if (gspVoExtendInfoService == null) {
            gspVoExtendInfoService = SpringBeanUtils.getBean(GspVoExtendInfoService.class);
        }
        return gspVoExtendInfoService;
    }

    private ObjectMapper objectMapper;

    private ObjectMapper getObjectMapper() {
        if (objectMapper == null) {
            objectMapper = new ObjectMapper();
        }
        return objectMapper;
    }

    // endregion

    /**
     * 转换为Vo实体
     */
    public GspViewModel createVo(GspBusinessEntity be, HashMap<String, String> configs,
                                 String bePkgName, String voGenerattingAssembly) {
        GspViewModel vo = ConvertUtils
                .convertToViewModel(be, bePkgName, be.getID(), voGenerattingAssembly).clone();
        handleApprovalConfig(vo, configs);
        return vo;
    }

    /**
     * 保存Vo实体
     */
    public String saveVoRt(GspViewModel vo, String bizObjectId, String nameSpace) {
        checkBeforeSave(vo.getGeneratedConfigID(), vo.getId(), vo.getCode());
        GspMetadata metadata = new GspMetadata();
        metadata.setContent(vo);
        MetadataHeader header = createMetadataHeader(vo, bizObjectId, nameSpace);
        metadata.setHeader(header);
        getCustomizationService().save(metadata);
        // todo:LCM提供保存后扩展前，自行调用
        this.saveGspVoExtendInfo(metadata);
        return vo.getID();
    }

    /**
     * 根据BEMeta获取VOGeneratingAssembly属性
     */
    public String getVoMetaGeneratingAssembly(GspMetadata beMetadata) {
        String beNameSpace = beMetadata.getHeader().getNameSpace();
        return beNameSpace;
    }

    /**
     * 已过期, 请使用{@link #checkBeforeSave(String, String, String)}
     */
    @Deprecated
    public void checkBeforeSave(String configId, String id) {
        //提示信息用于前端显示, 用户可以理解编号但很难理解configId,
        GspVoExtendInfo info = this.getGspVoExtendInfoService().getVoExtendInfoByConfigId(configId);

        Boolean checkResult = info == null || info.getId().equals(id);
        if (!checkResult) {
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0092, null, configId);
        }
    }


    /**
     * 保存前校验 todo:临时仅校验运行时表中的Vo元数据,不全，不包含部署在server目录的
     */
    public void checkBeforeSave(String configId, String id, String code) {
        //提示信息用于前端显示, 用户可以理解编号但很难理解configId,
        GspVoExtendInfo info = this.getGspVoExtendInfoService().getVoExtendInfoByConfigId(configId);

        Boolean checkResult = info == null || info.getId().equals(id);
        if (!checkResult) {
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0093, null, code);
        }
    }

    /**
     * 加载运行时元数据
     */
    public GspMetadata getRtMetadata(String metadataId) {
        CheckInfoUtil.checkNessaceryInfo("metadataId", metadataId);
        GspMetadata meta = MetadataUtil.getCustomMetadata(metadataId);
        if (meta == null || meta.getContent() == null) {
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0094, null, metadataId);
        }
        return meta;
    }

    // region 私有方法
    private void handleApprovalConfig(GspViewModel vo, HashMap<String, String> configs) {
        String config = getConfig(configs, VOGUIDE_EXTEND_CONFIG_APPROVAL);
        if (CheckInfoUtil.checkNull(config)) {
            return;
        }
        try {
            JsonNode node = getObjectMapper().readTree(config);
            JsonNode enableNode = node.get("enable");
            if (enableNode == null) {
                return;
            }
            Boolean enable = enableNode.booleanValue();
            if (!enable) {
                return;
            }
            //
            ApprovalLogType approvalLogType = getObjectMapper().readValue(node.get("approveType").asText(), ApprovalLogType.class);
            String entityCode = node.get("entity").get("code").textValue();
            String fieldLabelId = node.get("field").get("code").textValue();
            boolean includeBacklog;
            if (node.get("includeBacklog") == null) {
                includeBacklog = false;
            } else {
                includeBacklog = node.get("includeBacklog").booleanValue();
            }
            addApprovalLog(vo, approvalLogType, entityCode, fieldLabelId, includeBacklog);
        } catch (JsonProcessingException e) {
            throw new ViewModelException(e);
        }
    }

    private void addApprovalLog(GspViewModel vo, ApprovalLogType approvalLogType, String entityCode, String fieldLabelId, boolean includeBacklog) {
        switch (approvalLogType) {
            case ProcessInstant:
                getAccessoryService().addApprovalComments(vo, entityCode, fieldLabelId, includeBacklog);
                break;
            case BIllCode:
                getAccessoryService().addApprovalWorkItenLogs(vo, entityCode, fieldLabelId, includeBacklog);
                break;
            default:
                throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0095, null, approvalLogType.toString());
        }
    }

    private String getConfig(HashMap<String, String> configs, String key) {
        if (!configs.containsKey(key)) {
            return "";
        }
        String config = configs.get(key);
        return config;
    }

    private MetadataHeader createMetadataHeader(GspViewModel vo, String bizObjectId,
                                                String nameSpace) {
        MetadataHeader header = new MetadataHeader();
        header.setId(vo.getId());
        header.setCode(vo.getCode());
        header.setName(vo.getName());
        header.setBizobjectID(bizObjectId);
        header.setNameSpace(nameSpace);
        header.setType(VOGUIDE_VO_METADATATYPE);
        return header;
    }

    private void saveGspVoExtendInfo(GspMetadata voMeta) {
        List<GspVoExtendInfo> list = new ArrayList<>();
        list.add(getVoDataExtendInfo(voMeta));
        getGspVoExtendInfoService().saveGspVoExtendInfos(list);
    }

    private GspVoExtendInfo getVoDataExtendInfo(GspMetadata voMeta) {
        GspVoExtendInfo info = new GspVoExtendInfo();
        GspViewModel vo = (GspViewModel) voMeta.getContent();
        GspVoExtendInfo infoTemp = getGspVoExtendInfoService().getVoExtendInfo(vo.getId());
        if (infoTemp == null || !vo.getGeneratedConfigID().equals(info.getConfigId())) {
            info.setId(vo.getId());
            info.setConfigId(vo.getGeneratedConfigID());
            info.setBeSourceId(vo.getMapping().getTargetMetadataId());
            info.setCreatedOn(Date.from(CAFContext.current.getCurrentDateTime().toInstant()));
            info.setLastChangedOn(Date.from(CAFContext.current.getCurrentDateTime().toInstant()));
            return info;
//      info.setCreatedBy(CAFContext.current.getCurrentSession().getUserName());
//      info.setLastChangedBy(CAFContext.current.getCurrentSession().getUserName());
        } else {
//      infoTemp.setLastChangedBy(CAFContext.current.getCurrentSession().getUserName());
            infoTemp.setLastChangedOn(Date.from(CAFContext.current.getCurrentDateTime().toInstant()));
            return infoTemp;

        }

    }
    // endregion
}
